﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//
using DHNetSDK;
using DHPlaySDK;
using Microsoft.Win32;
using System.Diagnostics;


namespace SurveillanceLib
{
    /// <summary>
    /// 大华设备
    /// </summary>
    public class DH_Driver : DriverBase
    {
        #region Private Fields

        // 定义的回调代理相当于全局变量
        private fDisConnect _cbDisConnect = _fDisConnectCallBack;
        private fDownLoadPosCallBack _cbDownLoadPos = _fDownLoadPosCallBack;
        private fDataCallBack _cbData = _fDataCallBack;
        private AVIConvertCallback _cbAVIConvert = _fAVIConvertCallback;

        /// <summary>
        /// 断线回调函数,参见委托:DHNetSDK.fDisConnect【Static】
        /// </summary>
        private static Action<int, StringBuilder, int, IntPtr> _fDisConnectAction;

        /// <summary>
        /// 下载进度回调函数【Static】
        /// </summary>
        private static Action<int, uint, uint, IntPtr> _fDownLoadPosAction;

        /// <summary>
        /// 实时监视数据回调函数【Static】
        /// </summary>
        private static Action<int, uint, IntPtr, uint, uint> _fDownLoadDataAction;

        /// <summary>
        /// 文件转换回调函数【Static】
        /// </summary>
        private static Action<int, int, int, bool, string> _fAVIConvertAction;

        #endregion

        #region Private Methods
        /// <summary>
        /// 将 DateTime 转换成 NET_TIME
        /// </summary>
        /// <param name="datetime"></param>
        /// <returns></returns>
        private NET_TIME _convertDateTime2NET_TIME(DateTime datetime)
        {
            return new NET_TIME()
            {
                dwYear = datetime.Year,
                dwMonth = datetime.Month,
                dwDay = datetime.Day,
                dwHour = datetime.Hour,
                dwMinute = datetime.Minute,
                dwSecond = datetime.Second,
            };
        }

        /// <summary>
        /// 断线回调函数，设备断开连接处理，回调出当前网络已经断开的设备, 对调用SDK的ClIENT_LogOut()函数主动断开的设备不回调【Static】
        /// </summary>
        /// <param name="lLoginID"></param>
        /// <param name="pchDVRIP"></param>
        /// <param name="nDVRPort"></param>
        /// <param name="dwUser"></param>
        private static void _fDisConnectCallBack(int lLoginID, StringBuilder pchDVRIP,
            int nDVRPort, IntPtr dwUser)
        {
#if DEBUG
            Debug.WriteLine("设备自动断开连接！");
#endif
            try
            {
                if (_fDisConnectAction != null)
                    _fDisConnectAction(lLoginID, pchDVRIP, nDVRPort, dwUser);
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
            }
        }

        /// <summary>
        /// 进度回调函数【Static】
        /// </summary>
        /// <param name="lPlayHandle">播放句柄:CLIENT_PlayBackByRecordFile返回值</param>
        /// <param name="dwTotalSize">指本次播放总大小，单位为KB</param>
        /// <param name="dwDownLoadSize">指已经播放的大小，单位为KB，当其值为-1时表示本次回防结束</param>
        /// <param name="dwUser">用户数据</param>
        private static void _fDownLoadPosCallBack(int lPlayHandle, uint dwTotalSize,
            uint dwDownLoadSize, IntPtr dwUser)
        {
            try
            {
                if (_fDownLoadPosAction != null)
                    _fDownLoadPosAction(lPlayHandle, dwTotalSize, dwDownLoadSize, dwUser);
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
            }
        }

        /// <summary>
        /// 实时监视数据回调【Static】
        /// </summary>
        /// <param name="lRealHandle">实时监视ID</param>
        /// <param name="dwDataType">标识回调出来的数据类型, 只有dwFlag设置标识的数据才会回调出来： 0:原始数据(与SaveRealData保存的数据一致); 1:标准视频数据;2:yuv数据 3:pcm音频数据</param>
        /// <param name="pBuffer">回调数据,根据数据类型的不同每次回调不同的长度的数据,除类型0, 其他数据类型都是按帧,每次回调一帧数据</param>
        /// <param name="dwBufSize">回调数据的长度, 根据不同的类型, 长度也不同, (单位字节)</param>
        /// <param name="dwUser">用户数据，就是上面输入的用户数据</param>
        /// <returns>本回调函数的返回值会影响SDK的内部操作： 1:代表回调成功，没什么特殊情况都应该返回这个值 0:代表应用程序缓冲满，网络SDK将停顿一小会（ms级），然后回调同一数据，一般用于数据速度控制。-1:代表系统出错，将直接结束回放线程，慎用</returns>
        private static int _fDataCallBack(int lRealHandle, uint dwDataType, IntPtr pBuffer,
            uint dwBufSize, uint dwUser)
        {
            try
            {
                if (_fDownLoadDataAction != null)
                    _fDownLoadDataAction(lRealHandle, dwDataType, pBuffer, dwBufSize, dwUser);
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
            }

            return 1;
        }

        /// <summary>
        /// 文件转换回调函数【Static】
        /// </summary>
        /// <param name="nPort"></param>
        /// <param name="IMediaChangeType"></param>
        /// <param name="pUserData"></param>
        /// <param name="pbIfContinue"></param>
        /// <param name="sNewFileName"></param>
        private static void _fAVIConvertCallback(int nPort, int IMediaChangeType,
            int pUserData, bool pbIfContinue, string sNewFileName)
        {
            try
            {
                if (_fAVIConvertAction != null)
                    _fAVIConvertAction(nPort, IMediaChangeType, pUserData, pbIfContinue, sNewFileName);
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
            }
        }
        #endregion

        /// <summary>
        /// 初始化SDK
        /// </summary>
        /// <param name="cbDisConnect">断线回调函数,参见委托:DHNetSDK.fDisConnect</param>
        /// <param name="dwUser">用户数据,没有数据请使用IntPtr.Zero</param>
        /// <returns>true:成功;false:失败</returns>
        public override bool InitializeData(Action<int, StringBuilder, int, IntPtr> cbDisConnect,
            IntPtr dwUser)
        {
            try
            {
                _fDisConnectAction = cbDisConnect; // 断线回调函数
                return DHClient.DHInit(_cbDisConnect, dwUser); // 初始化状态
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return false;
            }
        }

        /// <summary>
        /// 设备字符编码格式[默认为:gb2312,其他字符编码请通过本函数设置]
        /// </summary>
        /// <param name="encodingString">字符编码字符串，参见MSDN中的Encoding</param>
        public override void SetEncoding(string encodingString)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(encodingString))
                    DHClient.DHSetEncoding(LANGUAGE_ENCODING.gb2312); // 字符编码格式设置，默认为 gb2312 字符编码，如果为其他字符编码请设置
                else
                    DHClient.DHSetEncoding(encodingString);
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
            }
        }

        /// <summary>
        /// 注册用户到设备，当设备端把用户设置为复用（设备默认的用户如admin,不能设置为复用），
        /// 则使用该帐号可以多次向设备注册
        /// </summary>
        /// <param name="pchDVRIP">设备IP</param>
        /// <param name="wDVRPort">设备端口</param>
        /// <param name="pchUserName">用户名</param>
        /// <param name="pchPassword">用户密码</param>
        /// <param name="lpDeviceInfo">设备信息,属于输出参数</param>
        /// <param name="error">返回登录错误码</param>
        /// <returns>失败返回0，成功返回设备ID</returns>
        public override string Login(string pchDVRIP, ushort wDVRPort,
            string pchUserName, string pchPassword, out NetDeviceInfoStruct lpDeviceInfo,
            out int error)
        {
            try
            {
                NET_DEVICEINFO deviceInfo = new NET_DEVICEINFO(); // 设备用户信息获得
                int pLoginID = DHClient.DHLogin(pchDVRIP, wDVRPort, pchUserName, pchPassword,
                        out deviceInfo, out error); // 设备用户登录 ID
                lpDeviceInfo = new NetDeviceInfoStruct()
                {
                    byAlarmInPortNum = deviceInfo.byAlarmInPortNum,
                    byAlarmOutPortNum = deviceInfo.byAlarmOutPortNum,
                    byChanNum = deviceInfo.byChanNum,
                    byDiskNum = deviceInfo.byDiskNum,
                    byDVRType = deviceInfo.byDVRType,
                    sSerialNumber = deviceInfo.sSerialNumber,
                };

                if (pLoginID <= 0)
                    return string.Empty;
                else
                    return pLoginID.ToString();
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                lpDeviceInfo = new NetDeviceInfoStruct();
                error = 0;
                return string.Empty;
            }
        }

        /// <summary>
        /// 注销设备用户
        /// </summary>
        /// <param name="lLoginID">设备用户登录ID:DHNetSDK.DHClient.CLIENT_Login
        /// (System.String,System.UInt16,System.String,System.String,
        /// DHNetSDK.NET_DEVICEINFO@,System.Int32@)的返回值</param>
        /// <returns>true:成功;false:失败</returns>
        public override bool Logout(string lLoginID)
        {
            try
            {
                int outLoginID;
                if (int.TryParse(lLoginID, out outLoginID))
                    return DHClient.DHLogout(outLoginID);
                else
                    return false;
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return false;
            }
        }

        /// <summary>
        /// 清空SDK, 释放占用的资源，在所有的SDK函数之后调用
        /// </summary>
        public override void CleanUp()
        {
            try
            {
                DHClient.DHCleanup();
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
            }
        }

        /// <summary>
        /// 最后操作信息[最后操作错误和成功]
        /// </summary>
        /// <param name="pErrInfoFormatStyle">最后操作信息显示格式</param>
        /// <returns>成功返回操作信息</returns>
        public override string GetLastOperationInfo(string pErrInfoFormatStyle)
        {
            try
            {
                return DHClient.LastOperationInfo.ToString(pErrInfoFormatStyle);
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return string.Empty;
            }
        }

        /// <summary>
        /// 启动实时监视
        /// </summary>
        /// <param name="lLoginID">设备用户登录ID:DHNetSDK.DHClient.CLIENT_Login
        /// (System.String,System.UInt16,System.String,System.String,
        /// DHNetSDK.NET_DEVICEINFO@,System.Int32@)的返回值</param>
        /// <param name="nChannelID">通道ID</param>
        /// <param name="hWnd">显示容器窗口句柄</param>
        /// <returns>失败返回空，成功返回实时监视ID(实时监视句柄)</returns>
        public override string RealPlay(string lLoginID, int nChannelID, IntPtr hWnd)
        {
            try
            {
                int pRealPlayHandle = 0, outLoginID;
                if (int.TryParse(lLoginID, out outLoginID))
                    pRealPlayHandle = DHClient.DHRealPlay(outLoginID, nChannelID, hWnd);
                else
                    return string.Empty;

                if (pRealPlayHandle <= 0)
                    return string.Empty;
                else
                    return pRealPlayHandle.ToString();
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return string.Empty;
            }
        }

        /// <summary>
        /// 停止实时监视
        /// </summary>
        /// <param name="lRealHandle">实时监视句柄:DHNetSDK.DHClient.CLIENT_RealPlay
        /// (System.Int32,System.Int32,System.IntPtr)的返回值</param>
        /// <returns>true:成功;false:失败</returns>
        public override bool StopRealPlay(string lRealHandle)
        {
            try
            {
                int outRealHandle;
                if (int.TryParse(lRealHandle, out outRealHandle))
                    return DHClient.DHStopRealPlay(outRealHandle);
                else
                    return false;
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return false;
            }
        }

        /// <summary>
        /// 开始流数据录像。只对流模式有用，在 PLAY_Play 之后调用
        /// </summary>
        /// <param name="nPort">播放器通道号</param>
        /// <param name="sFileName">录像文件名，如果文件名中有不存在的文件夹，就创建该文件夹</param>
        /// <param name="idataType">0:原始数据流;1:AVI</param>
        /// <returns>true:成功;false:失败</returns>
        public override bool StartDataRecord(int nPort, string sFileName, int idataType)
        {
            try
            {
                return DHPlay.DHStartDataRecord(nPort, sFileName, idataType);
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return false;
            }
        }

        /// <summary>
        /// 停止流数据录像
        /// </summary>
        /// <param name="nPort">播放器通道号</param>
        /// <returns>true:成功;false:失败</returns>
        public override bool StopDataRecord(int nPort)
        {
            try
            {
                return DHPlay.DHStopDataRecord(nPort);
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return false;
            }
        }

        /// <summary>
        /// 云台控制
        /// </summary>
        /// <param name="lLoginID">设备用户登录ID:DHNetSDK.DHClient.CLIENT_Login(System.String,System.UInt16,System.String,System.String,DHNetSDK.NET_DEVICEINFO@,System.Int32@)的返回值</param>
        /// <param name="nChannelID">通道号</param>
        /// <param name="dwPTZCommand">云台控制命令PTZControlType[PTZ_****的命令]</param>
        /// <param name="dwStep">步进/速度</param>
        /// <param name="dwStop">是否停止</param>
        /// <returns>true:成功;false:失败</returns>
        public override bool PTZControl(string lLoginID, int nChannelID,
            string dwPTZCommand, ushort dwStep, bool dwStop)
        {
            try
            {
                PTZ_CONTROL outPTZCommand;
                if (!Enum.TryParse<PTZ_CONTROL>(dwPTZCommand, true, out outPTZCommand))
                    return false;

                int outLoginID;
                if (int.TryParse(lLoginID, out outLoginID))
                    return DHClient.DHPTZControl(outLoginID, nChannelID, outPTZCommand, dwStep, dwStop);
                else
                    return false;
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return false;
            }
        }

        /// <summary>
        /// 保存图片,对显示图像进行瞬间抓图，只有打开图像的函数参数hWnd有效时该函数获取的参数才有效，否则无意义
        /// </summary>
        /// <param name="lPlayHandle">CLIENT_RealPlay的返回值</param>
        /// <param name="phPicFileName">位图文件名，当前只支持BMP位图</param>
        /// <returns>true:成功;false:失败</returns>
        public override bool CapturePicture(string lPlayHandle, string phPicFileName)
        {
            try
            {
                int outPlayHandle;
                if (int.TryParse(lPlayHandle, out outPlayHandle))
                    return DHClient.DHCapturePicture(outPlayHandle, phPicFileName);
                else
                    return false;
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return false;
            }
        }

        /// <summary>
        /// 查询录像文件
        /// </summary>
        /// <param name="lLoginID">设备用户登录句柄</param>
        /// <param name="nChannelId">通道ID</param>
        /// <param name="nRecordFileType">录像文件类型</param>
        /// <param name="tmStart">录像开始时间</param>
        /// <param name="tmEnd">录像结束时间</param>
        /// <param name="pchCardid">卡号,只针对卡号查询有效，其他情况下可以填NULL</param>
        /// <param name="nriFileinfo">返回的录像文件信息，是一个NET_RECORDFILE_INFO结构数组[录像文件信息为指定条]</param>
        /// <param name="maxlen">nriFileinfo缓冲的最大长度;[单位字节，大小为结构数组维数*sizeof(NET_RECORDFILE_INFO),数组维为大小等于1，建议小于２００]</param>
        /// <param name="filecount">返回的文件个数,属于输出参数最大只能查到缓冲满为止的录像记录</param>
        /// <param name="waittime">等待时间</param>
        /// <param name="bTime">是否按时间查(目前无效)</param>
        /// <returns>true:成功;false:失败</returns>
        public override bool QueryRecordFile(string lLoginID, int nChannelId,
            string nRecordFileType, DateTime tmStart, DateTime tmEnd,
            string pchCardid, ref NetRecordFileInfoStruct[] nriFileinfo,
            int maxlen, out int filecount, int waittime, bool bTime)
        {
            filecount = 0;

            try
            {
                RECORD_FILE_TYPE outRecordFileType;
                if (!Enum.TryParse<RECORD_FILE_TYPE>(nRecordFileType, true, out outRecordFileType))
                    return false;

                nriFileinfo = new NetRecordFileInfoStruct[SurveillanceUtilities.FILES_MAXCOUNT];
                NET_RECORDFILE_INFO[] recordFileInfos = new NET_RECORDFILE_INFO[SurveillanceUtilities.FILES_MAXCOUNT]; // 录像文件信息

                int outLoginID;
                if (int.TryParse(lLoginID, out outLoginID))
                {
                    bool result = DHClient.DHQueryRecordFile(outLoginID, nChannelId, outRecordFileType,
                        tmStart, tmEnd, pchCardid, ref recordFileInfos, maxlen, out filecount,
                        waittime, bTime);

                    for (int i = 0; i < recordFileInfos.Length && i < filecount; i++)
                    {
                        nriFileinfo[i] = new NetRecordFileInfoStruct()
                        {
                            ch = recordFileInfos[i].ch,
                            driveno = recordFileInfos[i].driveno,
                            endtime = recordFileInfos[i].endtime.ToDateTime(),
                            filename = recordFileInfos[i].filename,
                            nRecordFileType = recordFileInfos[i].nRecordFileType,
                            size = recordFileInfos[i].size,
                            startcluster = recordFileInfos[i].startcluster,
                            starttime = recordFileInfos[i].starttime.ToDateTime(),
                        };
                    }

                    return result;
                }
                else
                    return false;
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return false;
            }
        }

        /// <summary>
        /// 按文件下载录像文件, 通过查询到的文件信息下载
        /// </summary>
        /// <param name="lLoginID">CLIENT_Login的返回值</param>
        /// <param name="lpRecordFile">录像文件信息</param>
        /// <param name="sSavedFileName">要保存的录像文件名，全路径</param>
        /// <param name="cbDownLoadPos">下载进度回调函数</param>
        /// <param name="dwUserData">下载进度回调用户自定义数据</param>
        /// <returns>成功返回下载ID，失败返回空</returns>
        public override string DownloadByRecordFile(string lLoginID, NetRecordFileInfoStruct lpRecordFile,
            string sSavedFileName, Action<int, uint, uint, IntPtr> cbDownLoadPos, IntPtr dwUserData)
        {
            try
            {
                int pDownloadByRecordFileHandle = 0, outLoginID;
                if (int.TryParse(lLoginID, out outLoginID))
                {
                    NET_RECORDFILE_INFO recordFileInfo = new NET_RECORDFILE_INFO()
                    {
                        ch = lpRecordFile.ch,
                        driveno = lpRecordFile.driveno,
                        endtime = _convertDateTime2NET_TIME(lpRecordFile.endtime),
                        filename = lpRecordFile.filename,
                        nRecordFileType = lpRecordFile.nRecordFileType,
                        size = lpRecordFile.size,
                        startcluster = lpRecordFile.startcluster,
                        starttime = _convertDateTime2NET_TIME(lpRecordFile.starttime),
                    };

                    _fDownLoadPosAction = cbDownLoadPos; // 进度回调函数
                    pDownloadByRecordFileHandle = DHClient.DHDownloadByRecordFile(outLoginID, recordFileInfo, sSavedFileName,
                        _cbDownLoadPos, dwUserData);

                    if (pDownloadByRecordFileHandle <= 0)
                        return string.Empty;
                    else
                        return pDownloadByRecordFileHandle.ToString();
                }
                else
                    return string.Empty;
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return string.Empty;
            }
        }

        /// <summary>
        /// 停止下载录像文件
        /// </summary>
        /// <param name="lFileHandle">CLIENT_DownloadByRecordFile的返回值</param>
        /// <returns>true:成功;false:失败</returns>
        public override bool StopDownload(string lFileHandle)
        {
            try
            {
                int outFileHandle;
                if (int.TryParse(lFileHandle, out outFileHandle))
                    return DHClient.DHStopDownload(outFileHandle);
                else
                    return false;
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return false;
            }
        }

        /// <summary>
        /// 录像文件转换成AVI格式
        /// </summary>
        /// <param name="nPort">通道号</param>
        /// <param name="filename">要保存的文件名，全路径</param>
        /// <param name="pAVIFunc">文件转换回调函数</param>
        /// <param name="pUserData">回调用户自定义数据</param>
        /// <returns>true:成功;false:失败</returns>
        public override bool StartAVIConvert(int nPort, string filename,
            Action<int, int, int, bool, string> pAVIFunc, int pUserData)
        {
            try
            {
                _fAVIConvertAction = pAVIFunc; // 文件转换回调函数
                return DHPlay.PLAY_StartAVIConvert(nPort, filename, _cbAVIConvert, pUserData);
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return false;
            }
        }

        /// <summary>
        /// 停止转换AVI录像文件
        /// </summary>
        /// <param name="nPort">通道号</param>
        /// <returns>true:成功;false:失败</returns>
        public override bool StopAVIConvert(int nPort)
        {
            try
            {
                return DHPlay.PLAY_StopAVIConvert(nPort);
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return false;
            }
        }

        /// <summary>
        /// 播放控制
        /// </summary>
        /// <param name="pPlayCom">播放命令: 1.PLAY_COMMAND.StopSound:停止声音</param>
        /// <returns>true:成功;false:失败</returns>
        public override bool PlayControl(string pPlayCom)
        {
            try
            {
                PLAY_COMMAND outPlayCommand;
                if (!Enum.TryParse<PLAY_COMMAND>(pPlayCom, true, out outPlayCommand))
                    return false;

                return DHPlay.DHPlayControl(outPlayCommand);
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return false;
            }
        }

        /// <summary>
        /// 播放控制
        /// </summary>
        /// <param name="pPlayCom">播放命令: 1.PLAY_COMMAND.Stop:停止; 2.PLAY_COMMAND.CloseFile:关闭文件; 3.PLAY_COMMAND.Pause:暂停播放;
        ///     4.PLAY_COMMAND.ReSume:继续播放; 5.PLAY_COMMAND.Fast:快放; 6.PLAY_COMMAND.Slow:慢放;
        ///     7.PLAY_COMMAND.OneByOne:单帧播放; 8.PLAY_COMMAND.PlaySound:播放声音; 9.PLAY_COMMAND.PlaySoundShare:共享播放声音;
        ///     10.PLAY_COMMAND.StopSoundShare:停止共享播放声音; 11.PLAY_COMMAND.OneByOneBack:单帧回放
        ///     12.PLAY_COMMAND.CloseStream:关闭数据流 13.PLAY_COMMAND.CloseStreamEx:关闭数据流(音视频分开方式打开流)</param>
        /// <param name="nPort">播放通道号</param>
        /// <returns>true:成功;false:失败</returns>
        public override bool PlayControl(string pPlayCom, int nPort)
        {
            try
            {
                PLAY_COMMAND outPlayCommand;
                if (!Enum.TryParse<PLAY_COMMAND>(pPlayCom, true, out outPlayCommand))
                    return false;

                return DHPlay.DHPlayControl(outPlayCommand, nPort);
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return false;
            }
        }

        /// <summary>
        /// 播放控制
        /// </summary>
        /// <param name="pPlayCom">播放命令: 1.PLAY_COMMAND.OpenFile:打开文件; 2.PLAY_COMMAND.CatchPic:抓图;</param>
        /// <param name="nPort">播放通道号</param>
        /// <param name="sFileName">打开/保存文件名</param>
        /// <returns>true:成功;false:失败</returns>
        public override bool PlayControl(string pPlayCom, int nPort, string sFileName)
        {
            try
            {
                PLAY_COMMAND outPlayCommand;
                if (!Enum.TryParse<PLAY_COMMAND>(pPlayCom, true, out outPlayCommand) ||
                    string.IsNullOrWhiteSpace(sFileName))
                    return false;

                return DHPlay.DHPlayControl(outPlayCommand, nPort, sFileName);
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return false;
            }
        }

        /// <summary>
        /// 播放控制
        /// </summary>
        /// <param name="pPlayCom">播放命令: 1.PLAY_COMMAND.Start:开始播放</param>
        /// <param name="nPort">播放通道号</param>
        /// <param name="hWnd">播放容器句柄</param>
        /// <returns>true:成功;false:失败</returns>
        public override bool PlayControl(string pPlayCom, int nPort, IntPtr hWnd)
        {
            try
            {
                PLAY_COMMAND outPlayCommand;
                if (!Enum.TryParse<PLAY_COMMAND>(pPlayCom, true, out outPlayCommand))
                    return false;

                return DHPlay.DHPlayControl(outPlayCommand, nPort, hWnd);
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return false;
            }
        }

        /// <summary>
        /// 播放控制
        /// </summary>
        /// <param name="pPlayCom">播放命令: 1.PLAY_COMMAND.OpenStream:打开流接口 2.PLAY_COMMAND.OpenStreamEx:以音视频分开输入的方式打开流</param>
        /// <param name="nPort">通道号</param>
        /// <param name="pFileHeadBuff">目前不使用，填NULL</param>
        /// <param name="nSize">目前不使用，填0</param>
        /// <param name="nBufPoolSize">设置播放器中存放数据流的缓冲区大小。 范围是SOURCE_BUF_MIN~ SOURCE_BUF_MAX。 一般设为900*1024，如果数据送过来相对均匀，可调小该值，如果数据传输不均匀，可增大该值</param>
        /// <returns>true:成功;false:失败</returns>
        public override bool PlayControl(string pPlayCom, int nPort, IntPtr pFileHeadBuff,
            uint nSize, uint nBufPoolSize)
        {
            try
            {
                PLAY_COMMAND outPlayCommand;
                if (!Enum.TryParse<PLAY_COMMAND>(pPlayCom, true, out outPlayCommand))
                    return false;

                return DHPlay.DHPlayControl(outPlayCommand, nPort, pFileHeadBuff, nSize, nBufPoolSize);
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return false;
            }
        }

        /// <summary>
        /// 设置流播放的模式。必须在播放之前设置
        /// </summary>
        /// <param name="nPort">播放器通道号</param>
        /// <param name="nMode">数据流播放模式: 0.PLAY_MODE.STREAME_REALTIME:最实时方式 1.PLAY_MODE.STREAME_FILE:最流畅方式</param>
        /// <returns>true:成功;false:失败</returns>
        public override bool SetStreamOpenMode(int nPort, string nMode)
        {
            try
            {
                PLAY_MODE outPlayMode;
                if (!Enum.TryParse<PLAY_MODE>(nMode, true, out outPlayMode))
                    return false;

                return DHPlay.DHSetStreamOpenMode(nPort, outPlayMode);
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return false;
            }
        }

        /// <summary>
        /// 回放播放控制:播放，暂停，停止，单步播放，单步停止，慢放，快放
        /// </summary>
        /// <param name="lPlayHandle">播放句柄</param>
        /// <param name="pPlayCommand">控制命令:参见PlayControlType</param>
        /// <returns>true:成功;false:失败</returns>
        public override bool PlayBackControl(string lPlayHandle, string pPlayCommand)
        {
            try
            {
                PLAY_CONTROL outPlayControl;
                if (!Enum.TryParse<PLAY_CONTROL>(pPlayCommand, true, out outPlayControl))
                    return false;

                int outPlayHandle;
                if (int.TryParse(lPlayHandle, out outPlayHandle))
                    return DHClient.DHPlayBackControl(outPlayHandle, outPlayControl);
                else
                    return false;
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return false;
            }
        }

        /// <summary>
        /// 回放播放控制:改变位置播放[即拖动播放，只有打开图像的函数参数hWnd有效时该函数获取的参数才有效，否则无意义]
        /// </summary>
        /// <param name="lPlayHandle">播放句柄</param>
        /// <param name="pPlayCommand">播放命令:SeekByBit,SeekByTime</param>
        /// <param name="offset">SeekByTime:相对文件开始处偏移时间,单位为秒;SeekByBit:相对文件开始处偏移字节;</param>
        /// <returns>true:成功;false:失败</returns>
        public override bool PlayBackControl(string lPlayHandle, string pPlayCommand, uint offset)
        {
            try
            {
                PLAY_CONTROL outPlayControl;
                if (!Enum.TryParse<PLAY_CONTROL>(pPlayCommand, true, out outPlayControl))
                    return false;

                int outPlayHandle;
                if (int.TryParse(lPlayHandle, out outPlayHandle))
                    return DHClient.DHPlayBackControl(outPlayHandle, outPlayControl, offset);
                else
                    return false;
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return false;
            }
        }

        /// <summary>
        /// 网络回放[注意:用户登录一台设备后，每通道同一时间只能播放一则录像,不能同时播放同一通道的多条记录]
        /// </summary>
        /// <param name="lLoginID">设备用户登录句柄</param>
        /// <param name="lpRecordFile">录像文件信息, 当按时间播放是只需填充起始时间和结束时间, 其他项填0</param>
        /// <param name="hWnd">回放容器句柄</param>
        /// <param name="cbDownLoadPos">进度回调函数</param>
        /// <param name="dwUserData">用户自定义数据</param>
        /// <returns>成功返回网络回放ID，失败返回空</returns>
        public override string PlayBackByRecordFile(string lLoginID, ref NetRecordFileInfoStruct lpRecordFile,
            IntPtr hWnd, Action<int, uint, uint, IntPtr> cbDownLoadPos, IntPtr dwUserData)
        {
            try
            {
                int pPlayBackByRecordFile = 0, outLoginID;
                if (int.TryParse(lLoginID, out outLoginID))
                {
                    NET_RECORDFILE_INFO recordFileInfo = new NET_RECORDFILE_INFO() // 录像文件信息
                    {
                        ch = lpRecordFile.ch,
                        driveno = lpRecordFile.driveno,
                        endtime = _convertDateTime2NET_TIME(lpRecordFile.endtime),
                        filename = lpRecordFile.filename,
                        nRecordFileType = lpRecordFile.nRecordFileType,
                        size = lpRecordFile.size,
                        startcluster = lpRecordFile.startcluster,
                        starttime = _convertDateTime2NET_TIME(lpRecordFile.starttime),
                    };
                    _fDownLoadPosAction = cbDownLoadPos; // 进度回调函数

                    pPlayBackByRecordFile = DHClient.DHPlayBackByRecordFile(outLoginID, ref recordFileInfo,
                        hWnd, _cbDownLoadPos, dwUserData);

                    lpRecordFile.ch = recordFileInfo.ch;
                    lpRecordFile.driveno = recordFileInfo.driveno;
                    lpRecordFile.endtime = recordFileInfo.endtime.ToDateTime();
                    lpRecordFile.filename = recordFileInfo.filename;
                    lpRecordFile.nRecordFileType = recordFileInfo.nRecordFileType;
                    lpRecordFile.size = recordFileInfo.size;
                    lpRecordFile.startcluster = recordFileInfo.startcluster;
                    lpRecordFile.starttime = recordFileInfo.starttime.ToDateTime();

                    if (pPlayBackByRecordFile <= 0)
                        return string.Empty;
                    else
                        return pPlayBackByRecordFile.ToString();
                }
                else
                    return string.Empty;
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return string.Empty;
            }
        }

        /// <summary>
        /// 带数据回调的按录像文件回放扩展接口,每通道同一时间只能播放一则录像,不能同时播放同一通道的多条记录。
        /// 窗口参数（hWnd）有效时回调数据的返回值将被忽略，窗口参数(hWnd)为0时，需要注意回调函数的返回值，具体见回调函数说明。
        /// </summary>
        /// <param name="lLoginID">CLIENT_Login的返回值</param>
        /// <param name="lpRecordFile">录像文件信息</param>
        /// <param name="hWnd">回放容器句柄</param>
        /// <param name="cbDownLoadPos">进度回调函数</param>
        /// <param name="dwPosUser">进度回调函数用户数据</param>
        /// <param name="fDownLoadDataCallBack">数据回调函数</param>
        /// <param name="dwDataUser">数据回调函数用户数据</param>
        /// <returns>成功返回网络回放ID，失败返回空</returns>
        public override string PlayBackByRecordFile(string lLoginID, ref NetRecordFileInfoStruct lpRecordFile,
            IntPtr hWnd, Action<int, uint, uint, IntPtr> cbDownLoadPos, IntPtr dwPosUser,
            Action<int, uint, IntPtr, uint, uint> fDownLoadDataCallBack, IntPtr dwDataUser)
        {
            try
            {
                int pPlayBackByRecordFile = 0, outLoginID;
                if (int.TryParse(lLoginID, out outLoginID))
                {
                    NET_RECORDFILE_INFO recordFileInfo = new NET_RECORDFILE_INFO() // 录像文件信息
                    {
                        ch = lpRecordFile.ch,
                        driveno = lpRecordFile.driveno,
                        endtime = _convertDateTime2NET_TIME(lpRecordFile.endtime),
                        filename = lpRecordFile.filename,
                        nRecordFileType = lpRecordFile.nRecordFileType,
                        size = lpRecordFile.size,
                        startcluster = lpRecordFile.startcluster,
                        starttime = _convertDateTime2NET_TIME(lpRecordFile.starttime),
                    };
                    _fDownLoadPosAction = cbDownLoadPos; // 进度回调函数
                    _fDownLoadDataAction = fDownLoadDataCallBack; // 实时监视数据回调函数

                    pPlayBackByRecordFile = DHClient.DHPlayBackByRecordFile(outLoginID, ref recordFileInfo,
                        hWnd, _cbDownLoadPos, dwPosUser, _cbData, dwDataUser);

                    lpRecordFile.ch = recordFileInfo.ch;
                    lpRecordFile.driveno = recordFileInfo.driveno;
                    lpRecordFile.endtime = recordFileInfo.endtime.ToDateTime();
                    lpRecordFile.filename = recordFileInfo.filename;
                    lpRecordFile.nRecordFileType = recordFileInfo.nRecordFileType;
                    lpRecordFile.size = recordFileInfo.size;
                    lpRecordFile.startcluster = recordFileInfo.startcluster;
                    lpRecordFile.starttime = recordFileInfo.starttime.ToDateTime();

                    if (pPlayBackByRecordFile <= 0)
                        return string.Empty;
                    else
                        return pPlayBackByRecordFile.ToString();
                }
                else
                    return string.Empty;
            }
            catch (System.Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex.Message);
#endif
                return string.Empty;
            }
        }
    }
}
